
// 原始数据和响应式数据的双向缓存
let toProxy = new WeakMap(); // 根据原始数据查询响应后的数据
let toRaw = new WeakMap(); // 根据响应后的数据查询原始数据

// 缓存effect
let targetMap = new WeakMap();
const effectStack = []; // 存储effect

const baseHandler = {
    get(target, key) {
        const res = Reflect.get(target, key)
        // 依赖收集
        track(target, key)
        // 递归执行
        return typeof res === 'object' ? reactive(res) : res
    },
    set(target, key, val) {
        const info = {
            oldValue: target[key],
            newValue: val
        }
        const res = Reflect.set(target, key, val)
        // 触发更新操作
        trigger(target, key, info)
        return res
    }
}

// { (targetMap)
//     target: { (map)
//         name: [effect] (set)
//     }
// }
function track(target, key) {
    let effect = effectStack[effectStack.length - 1]
    // 初始化
    if (effect) {
        let depsMap = targetMap.get(target);
        if (depsMap === undefined) {
            depsMap = new Map();
            targetMap.set(target, depsMap);
        }
        let dep = depsMap.get(key)
        if (dep === undefined) {
            dep = new Set()
            depsMap.set(key, dep)
        }
        // 收集effect
        if (!dep.has(effect)) {
            dep.add(effect)
            effect.deps.push(dep)
        }
    }
}

function trigger(target, key, info) {
    // 触发更新
    const depsMap = targetMap.get(target)
    if (depsMap === undefined) {
        return
    }
    const effects = new Set() // 普通effect
    const computedRunners = new Set() // computed effect
    if (key) {
        let deps = depsMap.get(key)
        deps.forEach(effect => {
            if (effect.computed) {
                computedRunners.add(effect)
            } else {
                effects.add(effect)
            }
        })
    }
    const run = effect => effect()
    effects.forEach(run)
    computedRunners.forEach(run)
}

function reactive(target) {
    // 查询缓存，已经做过响应式的直接返回
    let observed = toProxy.get(target);
    if (observed) {
        return observed
    }
    if (toRaw.get(target)) {
        return target
    }

    // 没有缓存，创建响应式数据
    observed = new Proxy(target, baseHandler);
    // 设置缓存
    toProxy.set(target, observed)
    toRaw.set(observed, target)
    return observed
}

function effect(fn, options) {
    let e = createReactiveEffect(fn, options= {})
    if (!options.lazy) {
        e(); // effect初始化会执行一次
    }
    return e;
}

function createReactiveEffect(fn, options) {
    const effect = function effect(...args) {
        return run(effect, fn, args)
    }
    effect.deps = []
    effect.computed = options.computed
    effect.lazy = options.lazy
    return effect
}

function run(effect, fn, args) {
    if (effectStack.indexOf(effect) === -1) {
        try {
            effectStack.push(effect)
            return fn()
        }
        finally {
            effectStack.pop()
        }
    }
}

function computed(fn) {
    const runner = effect(fn, { computed: true, lazy: true })
    return {
        effect: runner,
        get value() {
            return runner()
        }
    }
}